import pygame   # 导入 pygame 库，用于所有图形和矩形操作
import os   # 导入 os 库，用于处理文件路径，确保能找到食物图片
import random   # 导入 random 库，用于在随机位置生成食物
import math     # 导入 math 库，用于数学计算，比如绘制特殊食物的形状
# 从main模块导入特殊食物配置
#from main import SPECIAL_FOOD_TYPES
"""循环导入，相互导入会报错"""
# 从constants.py导入需要的常量
# 从当前目录下的 constant.py 文件中，导入 SPECIAL_FOOD_TYPES 这个字典
from .constant import SPECIAL_FOOD_TYPES


# 食物类
# 方法： 放置/移除
# 点以25为单位
class Food:
    # 类的初始化方法（构造函数），当创建一个 Food 对象时会自动调用
    def __init__(self,base_dir):
        # 普通食物属性
        # 创建一个 pygame.Rect 对象来表示普通食物。Rect(x, y, 宽度, 高度)
        # 初始 x 坐标设为 -25，表示在屏幕外，即“不存在”
        self.normal_rect = pygame.Rect(-25, 0, 25, 25)

        # 特殊食物属性
        # 同样，创建一个 Rect 对象表示特殊食物，初始也在屏幕外
        self.special_rect = pygame.Rect(-25, 0, 25, 25)
        # 一个布尔值（True/False）标志，表示当前场上是否有特殊食物
        self.is_special_active = False  # 特殊食物是否激活
        # 存储特殊食物的类型 (会是 1, 2, 或 3)
        self.special_type = None  # 特殊食物类型（1/2/3）
        # 存储特殊食物在屏幕上的剩余时间
        self.special_remaining_time = 0  # 特殊食物剩余时间

        self.base_dir = base_dir  # 资源文件基础路径

        # 调用一个内部方法来加载食物的图片
        # 加载食物图片（带容错）
        self.image, self.original_image = self._load_food_image()
        """
        请去调用 self._load_food_image() 这个函数，这个函数会给我返回两个值，
        我把第一个值存到 self.image 变量里，第二个值存到 self.original_image 变量里
        2.self._load_food_image() (等号的右边)
        这是一个函数调用。self._load_food_image 是一个在这个类（class）内部定义的函数（也叫“方法”）。
        3.self.image, self.original_image = ... (等号的左边)
        这是一种 Python 特有的快捷语法，叫做 “元组解包” (Tuple Unpacking) 或 “多重赋值”。
        当等号右边的函数返回了多个值（比如 scaled_img, original_img）时，你就可以在等号左边按顺序放多个变量来“接收”它们
        4.self.original_image (原始图片):用来保存从硬盘加载的、未经修改的“底片”。
          self.image (当前图片):用来保存在游戏中实际显示的“工作副本”
        """

        # ========== 食物动画相关变量 ==========
        self.animation_time = 0     # 用于计算动画状态的计时器
        self.max_scale = 1.3  # 最大缩放比例
        self.min_scale = 0.7  # 最小缩放比例
        self.scale_speed = 0.05  # 缩放速度
        self.current_normal_scale = 1.0  # 普通食物当前缩放比例
        self.current_special_scale = 1.0  # 特殊食物当前缩放比例
        self.scale_direction = 1  # 1表示放大，-1表示缩小

    # 新增：设置特殊食物类型
    # 特殊食物操作
    def set_special(self, screen_x, special_type, snake_body, obstacles):
        """设置特殊食物位置和类型"""
        # 记录这次生成的特殊食物是什么类型
        self.special_type = special_type
        # 创建一个列表，用来存放所有可能的生成位置（x 和 y 坐标）
        allpos = []
        # 从 25 到 屏幕宽度-25，每隔 25 个像素，生成一个可能的坐标值
        for pos in range(25, screen_x - 25, 25):
            allpos.append(pos)

        # 随机选择位置，确保不与蛇身、障碍物和普通食物重叠,
        # 使用一个无限循环来随机尝试位置，直到找到一个合适的位置
        while True:
            self.special_rect.left = random.choice(allpos)
            """
            choice 是 Python 的 random (随机) 模块里的一个函数
            它的功能非常简单直接：从一个列表（或其他序列）中，随机挑选出“一个”元素。
            """
            self.special_rect.top = random.choice(allpos)

            overlap = False
            # 检查与蛇身重叠
            if self.special_rect in snake_body:
                overlap = True
                """
                1.当 overlap 变成 True 时，程序不仅仅是“不画特殊食物”
                2.它还会做一件更重要的事：重新再试一次,while 循环，
                3.overlap = True 时，意味着：“这次随机选的位置不行！重来！
                """

            # 检查与障碍物重叠
            for obs in obstacles:
                if self.special_rect.colliderect(obs["rect"]):
                    overlap = True
                    break

            # 检查与普通食物重叠
            if self.normal_rect.x != -25 and self.special_rect.colliderect(self.normal_rect):
                overlap = True

            if not overlap:
                break
            """
            overlap 仍然是 False (说明一次都没撞到)，
            那么 not overlap 就是 True，break 语句被执行，无限循环结束。程序成功找到了一个好位置！
            """
        # 标记场上已有特殊食物
        self.is_special_active = True
        self.special_remaining_time = 30  # 30秒倒计时

    def remove_special(self):
        """移除特殊食物"""
        # 把特殊食物的 x 坐标移到屏幕外
        self.special_rect.x = -25
        # 取消激活标记
        self.is_special_active = False
        # 清空类型
        self.special_type = None
        # 重置剩余时间
        self.special_remaining_time = 0

    # 定义一个内部方法（以下划线开头），用于加载图片
    def _load_food_image(self):
        """加载食物图片"""
        # 使用 os.path.join 拼接出食物图片的完整路径，这样做可以跨平台兼容
        food_path = os.path.join(self.base_dir, "food.png")
        # 使用 try...except 结构来处理可能发生的错误（比如图片文件不存在）
        try:
            # 尝试加载图片
            img = pygame.image.load(food_path)
            # 如果成功，返回加载的图片（两份，一份用于操作，一份保留原样）
            return img, img
        # 如果 try 部分的代码出错
        except Exception as e:
            # 就在控制台打印错误信息，提示用户缺少文件
            print(f"❌ 食物图片缺失！请将 food.png 放在 {self.base_dir} 目录")
            print(f"   错误详情：{str(e)}")
            # 返回 None，表示没有加载到图片
            return None, None

    # 普通食物操作
    # 定义一个方法，用于移除普通食物
    def remove_normal(self):
        """将普通食物移到屏幕外（被吃掉后）"""
        # 把普通食物的 x 坐标移到屏幕外
        self.normal_rect.x = -25

    # 生成食物时避开蛇身和动态障碍物和特殊食物
    def set_normal(self, screen_x, snake_body, obstacles):
        """设置普通食物位置"""
        # 只有在场上没有普通食物时（x坐标为-25），才生成新的
        if self.normal_rect.x == -25:
            # (这部分逻辑和 set_special 完全一样，也是为了找到一个不重叠的安全位置)
            allpos = []
            # 不靠墙太近 25 ~ SCREEN_X-25 之间
            for pos in range(25, screen_x - 25, 25):
                allpos.append(pos)

            # 随机选择位置，直到找到不与蛇身、障碍物和特殊食物重叠的位置
            while True:
                #choice从allpos里面随机选一个数
                self.normal_rect.left = random.choice(allpos)
                self.normal_rect.top = random.choice(allpos)

                # 检查是否与蛇身重叠
                overlap = False
                if self.normal_rect in snake_body:
                    overlap = True

                # 检查是否与障碍物重叠
                for obs in obstacles:
                    if self.normal_rect.colliderect(obs["rect"]):
                        overlap = True
                        break

                # 检查是否与特殊食物重叠
                if self.is_special_active and self.normal_rect.colliderect(self.special_rect):
                    overlap = True

                if not overlap:
                    break

    # ========== 添加食物动画更新方法 ==========
    def update(self):
        """更新食物的缩放动画和特殊食物倒计时"""
        # 更新缩放动画
        # 动画计时器加一
        self.animation_time += 1

        # 普通食物缩放
        # 更新普通食物的缩放比例
        # 当前比例 += 速度 * 方向
        self.current_normal_scale += self.scale_speed * self.scale_direction
        # 如果放大到超过最大值
        if self.current_normal_scale >= self.max_scale:
            # 就把比例固定在最大值
            self.current_normal_scale = self.max_scale
            # 并且把缩放方向改为缩小
            self.scale_direction = -1   #缩小
        # 如果缩小到小于最小值
        elif self.current_normal_scale <= self.min_scale:
            # 就把比例固定在最小值
            self.current_normal_scale = self.min_scale
            # 并且把缩放方向改为放大
            self.scale_direction = 1    #放大

        # 特殊食物缩放（与普通食物保持同步）
        # 让特殊食物的缩放和普通食物保持完全同步
        self.current_special_scale = self.current_normal_scale

        # 更新特殊食物倒计时
        # 如果场上有特殊食物
        if self.is_special_active:
            # 剩余时间减少。这里除以10是因为游戏帧率较高，这样可以减慢倒计时速度，使其接近真实秒数
            self.special_remaining_time -= 1/10  # 按帧率减少时间
            # 如果时间耗尽
            if self.special_remaining_time <= 0:
                # 就移除这个特殊食物
                self.remove_special()

    # 定义绘制方法，每一帧都会被调用
    # ========== 修改食物绘制方法 ==========
    def draw(self, screen):
        """绘制普通食物和特殊食物"""
        # 绘制普通食物
        # 如果普通食物在屏幕内
        if self.normal_rect.x != -25:  # 普通食物存在时
            # 并且图片已经成功加载
            if self.image:
                # 根据当前的缩放比例，计算出新的尺寸
                scaled_size = (int(25 * self.current_normal_scale), int(25 * self.current_normal_scale))
                """
                scaled_size = (新的宽度, 新的高度)
                1.current_normal_scale ,是“缩放比例”变量
                2.25 * self.current_normal_scale,是新的尺寸，
                3.int() 是 Python 的一个函数，意思是“取整数”
                4.scaled_size = (..., ...)scaled_size 是一个变量，用来存储这个计算结果。
                (...) 括号代表这是一个**“元组” (tuple)**。
                5.由于“新的宽度”和“新的高度”使用了完全相同的计算方法，这保证了图片在缩放时保持正方形（宽高比不变）
                """
                # 使用 pygame.transform.scale 函数，将原始图片缩放到新尺寸
                scaled_image = pygame.transform.scale(self.image, scaled_size)
                """
                1.transform 是 pygame 库里的一个模块，你可以把它想象成一个**“图像变换工具箱”**。
                这个“工具箱”里装满了各种用来改变图片（Surface 对象）的工具，比如：
                scale：缩放图片（放大或缩小）   rotate：旋转图片     flip：翻转图片
                2.self.image (第一个参数):这是“要被缩放的原始图片”。     scaled_size (第二个参数):这是“你希望缩放成的目标尺寸”
                3.scaled_image = ... (赋值):缩放工具 scale 在工作时，不会修改你的原始图片 self.image。
                相反，它会创建一张全新的、已经被缩放好的图片。
                scaled_image = 的意思就是，把这张“新图片”存到 scaled_image 这个变量里。

                """

                # 计算位置，使食物中心保持不变
                # 计算绘制的位置，这里有一个小技巧，是为了让食物缩放时中心点保持不变
                pos = (
                    self.normal_rect.x + (25 - scaled_size[0]) // 2,
                    self.normal_rect.y + (25 - scaled_size[1]) // 2
                )
                # 把缩放后的图片绘制到屏幕上
                screen.blit(scaled_image, pos)
            # 如果图片加载失败
            else:
                # 图片加载失败时的备选绘制
                scaled_size = (int(25 * self.current_normal_scale), int(25 * self.current_normal_scale))
                food_rect = pygame.Rect(
                    self.normal_rect.x + (25 - scaled_size[0]) // 2,
                    self.normal_rect.y + (25 - scaled_size[1]) // 2,
                    scaled_size[0],
                    scaled_size[1]
                )
                pygame.draw.rect(screen, (136, 0, 21), food_rect)   #暗红色方块
                pygame.draw.rect(screen, (255, 200, 0), food_rect, 2)     #2像素粗的黄/金色边框

        # 绘制特殊食物（如果激活）
        # 如果场上有特殊食物，并且它的类型是有效的
        if self.is_special_active and self.special_type in SPECIAL_FOOD_TYPES:
            # 从常量字典中获取这种食物的配置信息 (颜色、边框等)
            cfg = SPECIAL_FOOD_TYPES[self.special_type]
            # 计算缩放后的尺寸和位置
            scaled_size = (int(25 * self.current_special_scale), int(25 * self.current_special_scale))
            food_rect = pygame.Rect(
                self.special_rect.x + (25 - scaled_size[0]) // 2,
                self.special_rect.y + (25 - scaled_size[1]) // 2,
                scaled_size[0],
                scaled_size[1]
            )
            # 根据不同的食物类型，绘制不同的形状
            # 1. 绘制第一种特殊食物（蓝色边框紫色圆形）
            if self.special_type == 1:  # 类型1: 加速
                # 画一个实心圆
                pygame.draw.circle(screen, cfg["inner_color"],
                                   (food_rect.centerx, food_rect.centery),
                                   scaled_size[0] // 2)
                #  (缺少的第 5 个参数): 当你不提供第 5 个参数（边框粗细）时，
                #  pygame.draw.circle 默认会画一个实心的、被填充满的圆圈
                # 再画一个空心圆作为边框
                pygame.draw.circle(screen, cfg["border_color"],
                                   (food_rect.centerx, food_rect.centery),
                                   scaled_size[0] // 2, cfg["border_width"])

            # 2. 绘制第二种特殊食物（粉瓣柠檬黄花）
            elif self.special_type == 2:    # 类型2: 缩短
                # 绘制8片花瓣（正八边形分布）
                petal_radius = scaled_size[0] // 2
                center = (food_rect.centerx, food_rect.centery)
                # 循环 8 次，每隔 45 度画一个圆作为花瓣
                for angle in range(0, 360, 45):
                    rad = math.radians(angle)
                    """
                    1.radians 是 math (数学) 库里的一个函数，它的全名是 math.radians()。
                    2.计算机不喜欢用“度”。它们更喜欢用一种叫做**“弧度” (Radians)** 的单位。
                    “弧度” 也是一种度量角度的单位，它与 $\pi$ (圆周率) 挂钩。它们之间的换算关系是：180^\circ = \pi$ 弧度
                    3.math.radians() 函数有什么功能？
                    它的功能非常专一：把“度”转换成“弧度”
                    """
                    x = center[0] + petal_radius * math.cos(rad)    # 角度转弧度
                    """
                    1.以 center 为圆心，以 petal_radius 为半径，在 rad 这个角度上，帮我找到那个点的 (x, y) 坐标是多少
                    2.rad: 就是**“分针指向的角度”**（你上一行刚算出来的弧度）
                    """
                    y = center[1] + petal_radius * math.sin(rad)
                    """
                    1.math.sin(rad)：计算这个角度的正弦值。
                    2.petal_radius * math.sin(rad)：用“分针的长度”乘以这个“垂直比例”，就得到了**“针尖”相对于“圆心”的真实“垂直偏移量”
                    """
                    pygame.draw.circle(screen, cfg["petal_color"], (int(x), int(y)), petal_radius // 2)
                    #petal_radius: 就是时钟**“分针的长度”**（半径）。
                # 绘制花心，最后在中心画一个圆作为花心
                pygame.draw.circle(screen, cfg["center_color"], center, petal_radius // 3)
                """
                cfg 就是一个“全局配置字典”，用来集中管理你游戏中的所有设置，让代码更整洁、更易于维护
                """
            # 3. 绘制第三种特殊食物（浅绿色创意食物）
            elif self.special_type == 3:    # 类型3: 清障
                # 主体圆形
                # 先画一个带边框的圆形主体
                pygame.draw.circle(screen, cfg["inner_color"],
                                   (food_rect.centerx, food_rect.centery),
                                   scaled_size[0] // 2)
                # 在圆形内部画一个 "米" 字形图案
                pygame.draw.circle(screen, cfg["border_color"],
                                   (food_rect.centerx, food_rect.centery),
                                   scaled_size[0] // 2, cfg["border_width"])
                # 创意花纹（十字线+斜十字）
                pygame.draw.line(screen, cfg["pattern_color"],
                                 (food_rect.left + 5, food_rect.centery),
                                 (food_rect.right - 5, food_rect.centery), 2)
                pygame.draw.line(screen, cfg["pattern_color"],
                                 (food_rect.centerx, food_rect.top + 5),
                                 (food_rect.centerx, food_rect.bottom - 5), 2)
                pygame.draw.line(screen, cfg["pattern_color"],
                                 (food_rect.left + 5, food_rect.top + 5),
                                 (food_rect.right - 5, food_rect.bottom - 5), 2)
                """画了一条从左上到右下的对角线。
                4. 第四行：画一条“斜线” (/)"""
                pygame.draw.line(screen, cfg["pattern_color"],
                                 (food_rect.right - 5, food_rect.top + 5),
                                 (food_rect.left + 5, food_rect.bottom - 5), 2)
        """ 
        pygame.draw.line() 是 Pygame 库中 draw（绘制）模块里的一个**“画直线”**函数。
        要使用它，你必须告诉它 5 件事： pygame.draw.line(画在哪里, 用什么颜色, 起点坐标, 终点坐标, 线的粗细)
        """

